/**
This file is part of Gel2DE.

    Gel2DE is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Gel2DE is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with Gel2DE.  If not, see <http://www.gnu.org/licenses/>.

	Copyright (C) 2012, University of Bergen
*/

#include "GelImageViewer.h"

GelImageViewer::GelImageViewer(vtkRenderWindowInteractor* aInteractor)
{
	m_renderWindowInteractor = aInteractor;
	m_gelCorrelationAnalysis = NULL;
	m_gelImage = NULL;
	m_gelImageFixed = NULL;
	ConstructVTK();
}

GelImageViewer::~GelImageViewer(void)
{
	m_actor->Delete();
	m_actorFixed->Delete();
	m_renderer->Delete();
	m_shift->Delete();
	m_lut->Delete();
}

void GelImageViewer::SetGelCorrelationAnalysis(GelCorrelationAnalysis* aGelCorrelationAnalysis)
{
	m_gelCorrelationAnalysis = aGelCorrelationAnalysis;
}

void GelImageViewer::ResetCamera()
{
	m_renderer->ResetCamera();
}

void GelImageViewer::Clear()
{
	m_actor->VisibilityOff();
	m_actorFixed->VisibilityOff();
	m_rectangleActor->VisibilityOff();
}

void GelImageViewer::SetResultImageViewer(ResultImageViewer* aResultImageViewer)
{
	m_resultImageViewer = aResultImageViewer;
}

void GelImageViewer::SelectMovingImage(int aImageNumber)
{
	if (m_gelImage)
	{
		m_gelImage->SetReleaseDataFlags(true);
	}

	m_gelImage = m_gelCorrelationAnalysis->GetImage(aImageNumber);

	m_gelImage->SetReleaseDataFlags(false);
	
	GelImage::ImageType::Pointer image = m_gelImage->GetImage();

	m_connector->SetInput(image);
	m_connector->Update();

	m_leftButtonPressed = false;
	m_actor->VisibilityOn();
}

void GelImageViewer::SelectFixedImage(int aImageNumber)
{
	m_gelImageFixed = m_gelCorrelationAnalysis->GetImage(aImageNumber);
	m_gelImageFixed->SetReleaseDataFlags(false);

	GelImage::ImageType::Pointer image = m_gelImageFixed->GetImage();

	m_connectorFixed->SetInput(image);
	m_connectorFixed->Update();

	m_leftButtonPressed = false;
	m_actorFixed->VisibilityOn();

}

vtkRenderWindowInteractor* GelImageViewer::GetInteractor()
{
	return m_renderWindowInteractor;
}


void GelImageViewer::ShowStandard()
{
	std::vector<GelImage*>* gelVector = m_gelCorrelationAnalysis->GetGelImages();
	std::vector<GelImage*>::iterator i = gelVector->begin();
	
	m_shift->SetScale(1./256.);
	m_shift->SetOutputScalarTypeToUnsignedChar();
	m_shift->SetInput(m_connector->GetOutput());
	m_actor->SetInput(m_shift->GetOutput());

	m_shiftFixed->SetScale(1./256.);
	m_shiftFixed->SetOutputScalarTypeToUnsignedChar();
	m_shiftFixed->SetInput(m_connectorFixed->GetOutput());
	m_actorFixed->SetInput(m_shiftFixed->GetOutput());

	for(i; i != gelVector->end(); i++)
	{
		(*i)->UseStd();
	}
	m_gelImageFixed->UseStd();
	m_gelImage->Update();
	m_gelImageFixed->Update();	
}

void GelImageViewer::ShowData()
{
	std::vector<GelImage*>* gelVector = m_gelCorrelationAnalysis->GetGelImages();
	std::vector<GelImage*>::iterator i = gelVector->begin();

	m_shift->SetScale(1.);
	m_shift->SetOutputScalarTypeToUnsignedShort();
	m_actor->SetInput(m_vtkImageMapToColors->GetOutput());

	m_shiftFixed->SetScale(1.);
	m_shiftFixed->SetOutputScalarTypeToUnsignedShort();
	m_actorFixed->SetInput(m_vtkImageMapToColorsFixed->GetOutput());

	for(i; i != gelVector->end(); i++)
	{
		(*i)->UseData();
	}
	m_gelImageFixed->UseData();
	m_gelImage->Update();
	m_gelImageFixed->Update();

}

void GelImageViewer::SetFixedOpacity(double aAlpha)
{
	m_actorFixed->SetOpacity(aAlpha);
	Render();
}

void GelImageViewer::SetMovingOpacity(double aAlpha)
{
	m_actor->SetOpacity(aAlpha);
	Render();
}

void GelImageViewer::RoiEvent(unsigned long event)
{
	if(m_gelCorrelationAnalysis == NULL)
	{
		return;
	}

	if(m_gelCorrelationAnalysis->GetGelImages()->size() == 0)
	{
		return;
	}
	
	if(event == vtkCommand::LeaveEvent)
	{
		m_leftButtonPressed = FALSE;
		m_rightButtonPressed = FALSE;
	}

	if(event == vtkCommand::EnterEvent)
	{
		m_leftButtonPressed = FALSE;
		m_rightButtonPressed = FALSE;
	}

	if(event == vtkCommand::LeftButtonPressEvent)
	{
		m_leftButtonPressed = TRUE;
		GetInteractor()->GetEventPosition(m_prevPos);

		m_pointPicker->Pick(m_prevPos[0], m_prevPos[1], 0, m_renderer);
		m_pointPicker->GetPickPosition(m_currentPos);
		vtkProp3D* actor = m_pointPicker->GetProp3D();

		m_buttonDownPosition[0] = m_currentPos[0];
		m_buttonDownPosition[1] = m_currentPos[1];
		m_buttonDownPosition[2] = m_currentPos[2];
	}

	if(event == vtkCommand::LeftButtonReleaseEvent)
	{
		m_leftButtonPressed = FALSE;
	}

	if(event == vtkCommand::RightButtonPressEvent)
	{
		m_rightButtonPressed = TRUE;
		GetInteractor()->GetEventPosition(m_prevPos);
	}

	if(event == vtkCommand::RightButtonReleaseEvent)
	{
		m_rightButtonPressed = FALSE;
	}


	if(event == vtkCommand::MouseMoveEvent)
	{
		int currentPos[2];
		m_renderWindowInteractor->GetEventPosition(currentPos);
		double dx = (double)(m_prevPos[0] - currentPos[0]);
		double dy = (double)(m_prevPos[1] - currentPos[1]);

		if(m_leftButtonPressed)
		{
			//Draw rectangle
			updateRectangle(currentPos);
		}			

		Render();

		m_prevPos[0] = currentPos[0];
		m_prevPos[1] = currentPos[1];

	}

}


void GelImageViewer::RegisterEvent(unsigned long event)
{
	if(m_gelCorrelationAnalysis == NULL)
	{
		return;
	}

	if(m_gelCorrelationAnalysis->GetGelImages()->size() == 0)
	{
		return;
	}
	
	if(event == vtkCommand::LeaveEvent)
	{
		m_leftButtonPressed = FALSE;
		m_rightButtonPressed = FALSE;
	}

	if(event == vtkCommand::EnterEvent)
	{
		m_leftButtonPressed = FALSE;
		m_rightButtonPressed = FALSE;
	}

	if(event == vtkCommand::LeftButtonPressEvent)
	{
		m_leftButtonPressed = TRUE;
		GetInteractor()->GetEventPosition(m_prevPos);

		m_pointPicker->Pick(m_prevPos[0], m_prevPos[1], 0, m_renderer);
		m_pointPicker->GetPickPosition(m_currentPos);
		vtkProp3D* actor = m_pointPicker->GetProp3D();

		m_buttonDownPosition[0] = m_currentPos[0];
		m_buttonDownPosition[1] = m_currentPos[1];
		m_buttonDownPosition[2] = m_currentPos[2];
	}

	if(event == vtkCommand::RightButtonPressEvent)
	{
		m_rightButtonPressed = TRUE;
		GetInteractor()->GetEventPosition(m_prevPos);
	}

	if(event == vtkCommand::RightButtonReleaseEvent)
	{
		m_rightButtonPressed = FALSE;
	}


	if(event == vtkCommand::MouseMoveEvent)
	{
		int currentPos[2];
		m_renderWindowInteractor->GetEventPosition(currentPos);
		double dx = (double)(m_prevPos[0] - currentPos[0]);
		double dy = (double)(m_prevPos[1] - currentPos[1]);

		if(m_leftButtonPressed)
		{
			if(m_renderWindowInteractor->GetShiftKey())
			{
				double dxdy[2];
				dxdy[0] = dx;
				dxdy[1] = dy;
				GetGelImage()->Translate(dxdy);
			}
			else if(m_renderWindowInteractor->GetControlKey())
			{
				GetGelImage()->Rotate(dy*0.0005);
			}
			else
			{
				//Draw rectangle
				//updateRectangle(currentPos);
			}
		}			
		else if(m_rightButtonPressed)
		{
			GetGelImage()->Scale(dy*0.01);
		}

		Render();

		m_prevPos[0] = currentPos[0];
		m_prevPos[1] = currentPos[1];

	}

	if(event == vtkCommand::LeftButtonReleaseEvent)
	{
		m_leftButtonPressed = FALSE;
	}

}

void GelImageViewer::updateRectangle(int* currentPos)
{
	m_pointPicker->Pick(currentPos[0], currentPos[1], 0, m_renderer);
	m_pointPicker->GetPickPosition(m_currentPos);
	vtkProp3D* actor = m_pointPicker->GetProp3D();
	if(actor != NULL)
	{
		m_currentPos[0] = m_currentPos[0] + 0.5;
		m_currentPos[1] = m_currentPos[1] + 0.5;
	}


	vtkImageActor* imageactor = (vtkImageActor*)actor;
	if(imageactor)
	{
		GelCorrelationAnalysis::DataImageType::SizeType maxRegion = m_gelImage->GetImage()->GetLargestPossibleRegion().GetSize();
		//Check if it is inside the region, due to hack to get ITK/VTK mismatch invisible...
		if((int)m_currentPos[0] >= 0 && (int)m_currentPos[0] < maxRegion[0] && (int)m_currentPos[1] >= 0 && (int)m_currentPos[1] < maxRegion[1])
		{
			double buttonDownPos[2];
			double currentBoxPos[2];

			buttonDownPos[0] = floor(m_buttonDownPosition[0]) - 0.5;
			buttonDownPos[1] = floor(m_buttonDownPosition[1]) - 0.5;

			currentBoxPos[0] = floor(m_currentPos[0]) - 0.5;
			currentBoxPos[1] = floor(m_currentPos[1]) - 0.5;

			if(m_buttonDownPosition[0] < m_currentPos[0])
			{
				currentBoxPos[0] += 1;
			}
			else
			{
				buttonDownPos[0] += 1;
			}

			if(m_buttonDownPosition[1] < m_currentPos[1])
			{
				currentBoxPos[1] += 1;
			}
			else
			{
				buttonDownPos[1] += 1;
			}

			m_rect->InsertPoint(0, buttonDownPos[0], buttonDownPos[1], m_buttonDownPosition[2] + 0.1);
			m_rect->InsertPoint(1, currentBoxPos[0], buttonDownPos[1], m_buttonDownPosition[2] + 0.1);
			m_rect->InsertPoint(2, currentBoxPos[0], currentBoxPos[1], m_buttonDownPosition[2] + 0.1);
			m_rect->InsertPoint(3, buttonDownPos[0], currentBoxPos[1], m_buttonDownPosition[2] + 0.1);
			m_rect->Modified();

			if(m_resultImageViewer->HasResult())
			{
				m_resultImageViewer->UpdateRectangle(m_rect);	
				m_resultImageViewer->SetRectangleVisible(1);
			}
			m_rectangleActor->VisibilityOn();
		}
	}
}

void registerCallback(vtkObject *caller, unsigned long event, void* clientdata, void* callerdata)
{
	GelImageViewer *viewer = (GelImageViewer*)clientdata;
	viewer->RegisterEvent(event);
}

void roiselectCallback(vtkObject *caller, unsigned long event, void* clientdata, void* callerdata)
{
	GelImageViewer* viewer = (GelImageViewer*)clientdata;
	viewer->RoiEvent(event);
}

vtkCamera* GelImageViewer::GetCamera()
{
	return m_renderer->GetActiveCamera();
}

void GelImageViewer::Render()
{
	m_connector->Update();
	m_connectorFixed->Update();
	m_renderWindowInteractor->Render();
}

GelImage* GelImageViewer::GetGelImage()
{
	return m_gelImage;
}

void GelImageViewer::ConstructVTK()
{

	m_connector = ConnectorType::New();

	m_shift = vtkImageShiftScale::New();
	//shift->SetScale(1./256.);
	m_shift->SetScale(1.);
	//shift->SetOutputScalarTypeToUnsignedChar();
	m_shift->SetOutputScalarTypeToUnsignedShort();
	m_shift->SetInput(m_connector->GetOutput());

	m_vtkImageMapToColors = vtkImageMapToColors::New();
	m_lut = vtkWindowLevelLookupTable::New();
	m_lut->SetMinimumTableValue(0, 0, 0, 1);
	m_lut->SetMaximumTableValue(1, 1, 1, 1);
	m_lut->SetLevel(100);
	m_lut->SetWindow(100);
	m_lut->Build();

	m_vtkImageMapToColors->SetLookupTable(m_lut);
	
	m_vtkImageMapToColors->SetInput(m_shift->GetOutput());
	m_actor = vtkImageActor::New();
	m_actor->SetInput(m_vtkImageMapToColors->GetOutput());
	m_actor->InterpolateOff();

	m_renderer = vtkRenderer::New();
	m_renderer->AddActor(m_actor);

	double col[3];
	col[0] = 0.5;
	col[1] = 0.5;
	col[2] = 0.5;
	m_renderer->SetBackground(col);


	m_vtkCallbackCommand = vtkCallbackCommand::New();
	m_vtkCallbackCommand->SetCallback(registerCallback);
	m_vtkCallbackCommand->SetClientData(this);

	AddRegisterObserver();

	m_actorFixed = vtkImageActor::New();
	m_connectorFixed = ConnectorType::New();

	m_shiftFixed = vtkImageShiftScale::New();
	//shiftFixed->SetScale(1./256.); //todo: should be part of the gel image?
	//m_shiftFixed->SetOutputScalarTypeToUnsignedChar();
	m_shiftFixed->SetOutputScalarTypeToUnsignedShort();
	m_shiftFixed->SetInput(m_connectorFixed->GetOutput());
	m_vtkImageMapToColorsFixed = vtkImageMapToColors::New();
	m_vtkImageMapToColorsFixed->SetLookupTable(m_lut);
	m_vtkImageMapToColorsFixed->SetInput(m_shiftFixed->GetOutput());
	m_actorFixed->SetInput(m_vtkImageMapToColorsFixed->GetOutput());
	//m_actorFixed->SetInput(shiftFixed->GetOutput());
	m_renderer->AddActor(m_actorFixed);
	m_actorFixed->SetOpacity(0.);
	m_actorFixed->InterpolateOff();
	m_actor->SetOpacity(1.0);
	m_actor->VisibilityOff();
	m_actorFixed->VisibilityOff();

	InitializeRectangle();
	m_renderer->AddActor(m_rectangleActor);
	m_rectangleActor->VisibilityOff();

	m_pointPicker = vtkPropPicker::New();

	m_renderWindowInteractor->SetPicker(m_pointPicker);

}

void GelImageViewer::UpdateRectangle(vtkPoints* aPoints)
{
	for(int i = 0; i < aPoints->GetNumberOfPoints(); i++)
	{
		double point[3];
		aPoints->GetPoint(i, point);
		m_rect->InsertPoint(i, point);
	}
	m_rect->Modified();
	m_renderWindowInteractor->Render();
}

void GelImageViewer::SetRectangleVisible(int aVisible)
{
	m_rectangleActor->SetVisibility(aVisible);
	m_renderWindowInteractor->Render();
}

void GelImageViewer::SetWindow(double aWindow)
{
	m_lut->SetWindow(aWindow);
	m_lut->Build();
}

void GelImageViewer::SetLevel(double aLevel)
{
	m_lut->SetLevel(aLevel);
	m_lut->Build();
}

void GelImageViewer::AddRegisterObserver()
{

	vtkInteractorStyleUser *interactorStyle = vtkInteractorStyleUser::New();
	m_renderWindowInteractor->SetInteractorStyle(interactorStyle);
	m_renderWindowInteractor->GetRenderWindow()->AddRenderer(m_renderer);


	m_renderWindowInteractor->AddObserver(vtkCommand::MouseMoveEvent, m_vtkCallbackCommand);
	m_renderWindowInteractor->AddObserver(vtkCommand::LeftButtonPressEvent, m_vtkCallbackCommand);
	m_renderWindowInteractor->AddObserver(vtkCommand::LeftButtonReleaseEvent, m_vtkCallbackCommand);
	m_renderWindowInteractor->AddObserver(vtkCommand::RightButtonPressEvent, m_vtkCallbackCommand);
	m_renderWindowInteractor->AddObserver(vtkCommand::RightButtonReleaseEvent, m_vtkCallbackCommand);
	m_renderWindowInteractor->AddObserver(vtkCommand::LeaveEvent, m_vtkCallbackCommand);
	m_renderWindowInteractor->AddObserver(vtkCommand::EnterEvent, m_vtkCallbackCommand);
}

void GelImageViewer::RegisterMode()
{
	m_renderWindowInteractor->RemoveObserver(m_vtkCallbackCommand);
	m_vtkCallbackCommand->SetCallback(registerCallback);
	AddRegisterObserver();
}
void GelImageViewer::ROIMode()
{
	vtkInteractorStyleUser *interactorStyle = vtkInteractorStyleUser::New();
	m_renderWindowInteractor->SetInteractorStyle(interactorStyle);

	m_renderWindowInteractor->RemoveObserver(m_vtkCallbackCommand);
	m_vtkCallbackCommand->SetCallback(roiselectCallback);

	m_renderWindowInteractor->AddObserver(vtkCommand::MouseMoveEvent, m_vtkCallbackCommand);
	m_renderWindowInteractor->AddObserver(vtkCommand::LeftButtonPressEvent, m_vtkCallbackCommand);
	m_renderWindowInteractor->AddObserver(vtkCommand::LeftButtonReleaseEvent, m_vtkCallbackCommand);
	m_renderWindowInteractor->AddObserver(vtkCommand::RightButtonPressEvent, m_vtkCallbackCommand);
	m_renderWindowInteractor->AddObserver(vtkCommand::RightButtonReleaseEvent, m_vtkCallbackCommand);
	m_renderWindowInteractor->AddObserver(vtkCommand::LeaveEvent, m_vtkCallbackCommand);
	m_renderWindowInteractor->AddObserver(vtkCommand::EnterEvent, m_vtkCallbackCommand);
}

void GelImageViewer::ZoomMode()
{
	m_renderWindowInteractor->RemoveObserver(m_vtkCallbackCommand);
	m_renderWindowInteractor->SetInteractorStyle(vtkInteractorStyleImage::New());
}

void GelImageViewer::GetROIDefinition(GelCorrelationAnalysis::RGBImageType::RegionType* aRoiDefinition)
{
	GelCorrelationAnalysis::RGBImageType::SizeType roiSize;
	GelCorrelationAnalysis::RGBImageType::IndexType roiIndex;
	double p1[3];
	double p2[3];
	m_rect->GetPoint(0, p1);
	m_rect->GetPoint(2, p2);

	roiSize[0] = abs(p2[0] - p1[0]);
	roiSize[1] = abs(p2[1] - p1[1]);

	//The index has to be the smallest in each case
	if(p1[0] < p2[0]) roiIndex[0] = p1[0] + 1;
	else roiIndex[0] = p2[0] + 1;

	if(p1[1] < p2[1]) roiIndex[1] = p1[1] + 1;
	else roiIndex[1] = p2[1] + 1;

	//GelCorrelationAnalysis::DataImageType::RegionType roiDefinition;
	aRoiDefinition->SetIndex(roiIndex);
	aRoiDefinition->SetSize(roiSize);
	//return roiDefinition;
}


void GelImageViewer::InitializeRectangle()
{
	m_rect = vtkPoints::New();
	m_rect->SetNumberOfPoints(4);

	m_rect->InsertPoint(0, 0, 0, 0);
	m_rect->InsertPoint(1, 0, 100, 0);
	m_rect->InsertPoint(2, 100, 100, 0);
	m_rect->InsertPoint(3, 100, 0, 0);

	vtkPolyData* rectanglePolyData = vtkPolyData::New();
	rectanglePolyData->SetPoints(m_rect);
	vtkCellArray* rect = vtkCellArray::New();
	rect->InsertNextCell(5);
	rect->InsertCellPoint(0);
	rect->InsertCellPoint(1);
	rect->InsertCellPoint(2);
	rect->InsertCellPoint(3);
	rect->InsertCellPoint(0);

	rectanglePolyData->SetLines(rect);
	vtkPolyDataMapper* rectangleMapper = vtkPolyDataMapper::New();
	rectangleMapper->SetInput(rectanglePolyData);
	m_rectangleActor = vtkActor::New();
	m_rectangleActor->SetMapper(rectangleMapper);
	m_rectangleActor->GetProperty()->SetColor(1., 0., 0.);
}
